module Cocupu
  class Node
    attr_accessor :values
    attr_reader :conn
    def initialize(values)
      @conn = Thread.current[:cocupu_connection] 
      self.values = values
    end

    def self.create(values)
      node = Cocupu::Node.new(values)
      node.save
      node
    end
    
    # Find
    # @return Array of Cocupu::Nodes
    # @example
    #   Cocupu::Node.find{"my_identity", "pool_20", {'model_id' => 22} }
    def self.find(identity, pool, query_params)
      conn = Thread.current[:cocupu_connection]
      url = "/#{pool}/search.json"
      query_hash = query_params_to_refine_multi_query(query_params)
      query_hash[:marshall_nodes] = true
      #nodes_json = JSON.parse(conn.get(url,query_hash).body)
      query_response =  conn.get(url,query_hash).body
      nodes = results_from_refine_multi_query_response(query_response).map {|json| Cocupu::Node.new(json) }
      return nodes
    end

    # Return JSON nodes from HTTP response returned by multi query generated by #query_params_to_refine_multi_query
    def self.results_from_refine_multi_query_response(query_response)
      json_response = JSON.parse(query_response)
      json_response["q1"]["result"]
    end

    def self.query_params_to_refine_multi_query(query_params)
      query_params =  query_params.dup
      query_hash = {}
      if query_params["q"]
        query_hash["query"] = query_params.delete("q")
      else
        query_hash["query"] = ""
      end
      if query_params["model_name"]
        query_hash["type"] = query_params.delete("model_name")
        query_hash["type_strict"] = "should"
      end
      query_params.each_pair do |k,v|
        query_hash["properties"] ||= []
        query_hash["properties"]<< {p: k, v: v}
      end
      return {"queries" => {"q1" => query_hash}}
    end


    # Find or Create
    # @return Node
    # @example
    #   Cocupu::Node.find_or_create{'pool_id'=>"pool_20", "node" => {'model_id' => 22, 'data' => {'file_name'=>'my file.xls'}} }
    def self.find_or_create(values)
      conn = Thread.current[:cocupu_connection] 
      pool_id = values["pool_id"]
      response = conn.post("/pools/#{pool_id}/nodes/find_or_create.json", body: {node: values["node"]})
      raise "Error trying to find_or_create node: #{response.inspect}" unless response.code >= 200 and response.code < 300
      if (response['persistent_id'])
        result = self.new(response)
      end
      result
    end

    def self.import(values)
      conn = Thread.current[:cocupu_connection]
      pool_id = values["pool_id"]
      model_id = values["model_id"]
      post_params = {model_id:model_id, data: values["data"]}
      post_params[:key] = values["key"] if values["key"]
      conn.post("/pools/#{pool_id}/nodes/import.json", body: post_params)
    end

    def model_id
      values['model_id']
    end

    def identity
      values['identity_id']
    end

    def pool
      values['pool_id']
    end

    def url
      values['url'] ||= id ? "/pools/#{pool}/nodes/#{id}" : "/pools/#{pool}/nodes"
    end

    def url=(url)
      values['url'] = url
    end

    def id
      values['node_version_id']
    end

    def persistent_id=(id)
      values['persistent_id'] = id
    end
    
    def associations=(associations)
      values['associations'] = associations
    end
    
    def associations
      values['associations']
    end
    
    def data=(data)
      values["data"] = data
    end
        
    def data
      values["data"]
    end

    def persistent_id
      values['persistent_id']
    end

    def save
      response = if persistent_id 
        self.url = "#{url}/#{persistent_id}" unless self.url.include?(persistent_id)
        conn.put("#{url}.json", body: {node: values})
      else
        conn.post("#{url}.json", body: {node: values})
      end
      raise "Error saving models: #{response.inspect}" unless response.code >= 200 and response.code < 300
      if (response['persistent_id'])
        self.persistent_id = response['persistent_id']
        self.url = response['url']
      end
      values
    end

    def attach_file(file_name, file)
      raise RuntimeError, "You can't attach a file to an object that hasn't been persisted" unless persistent_id
      Cocupu::File.new(self, file_name, file)
    end

  end

end
